//
//  GWAssetsSnapshotStackView.m
//  GiganticWhale
//
//  Created by 裴烨烽 on 16/2/18.
//  Copyright © 2016年 GiganticWhale. All rights reserved.
//

#import "GWAssetsSnapshotStackView.h"

@interface GWAssetsSnapshotStackView (Private)
- (void)commonInitialisation;
- (void)calculateScalingToFitStack;
@end

#pragma mark Constants

#define SWSnapshotStackViewMatteWidth          7.0
#define SWSnapshotStackViewSingleShadowXOffset 5.0
#define SWSnapshotStackViewSingleShadowYOffset 5.0
#define SWSnapshotStackViewSingleShadowRadius  5.0
#define SWSnapshotStackViewSingleShadowTotalHeight (SWSnapshotStackViewSingleShadowYOffset + SWSnapshotStackViewSingleShadowRadius)
#define SWSnapshotStackViewStackShadowYOffset  2.0
#define SWSnapshotStackViewStackShadowRadius   6.0
#define SWSnapshotStackViewStackShadowTotalHeight ((2 * SWSnapshotStackViewStackShadowRadius) - SWSnapshotStackViewStackShadowYOffset)

@implementation GWAssetsSnapshotStackView
@dynamic image;
@dynamic displayAsStack;



- (UIImage *)image {
    return (m_image);
}

- (void)setImage:(UIImage *)image {
    m_image = image;
    
    if (nil != m_image) {
        m_imageAspect = m_image.size.width / m_image.size.height;
        if (YES == m_displayStack) {
            [self calculateScalingToFitStack];
        }
    }
    [self setNeedsDisplay];
}

- (BOOL)displayAsStack {
    return (m_displayStack);
}

- (void)setDisplayAsStack:(BOOL)displayAsStack {
    if (displayAsStack != m_displayStack) {
        m_displayStack = displayAsStack;
        if ((YES == m_displayStack) && (nil != m_image)) {
            [self calculateScalingToFitStack];
        }
        
        [self setNeedsDisplay];
    }
}

#pragma mark Instance Methods

- (id)initWithFrame:(CGRect)frame {
    if (nil != (self = [super initWithFrame:frame])) {
        [self commonInitialisation];
    }
    
    return (self);
}

//- (void)awakeFromNib {
//    [self commonInitialisation];
//}

- (void)commonInitialisation {
    m_snapshotPositions[0].angleRotation = 2.5;   // 2.0  // 3.0
    m_snapshotPositions[1].angleRotation = -3.0;   // 4.0  // -5.0
    m_snapshotPositions[2].angleRotation = 0.0;
    self.backgroundColor = [UIColor clearColor];
    m_shadowDirSign = 1.0;
    if (NSOrderedAscending == [[[UIDevice currentDevice] systemVersion] compare:@"3.2" options:NSNumericSearch]) {
        m_shadowDirSign = -1.0;
    }
}

- (void)drawRect:(CGRect)rect {
    if (nil == m_image) {
        return;
    }
    
    CGContextRef context = UIGraphicsGetCurrentContext ();
    
    CGPoint viewCenter =
    CGPointMake (CGRectGetMidX (self.bounds), CGRectGetMidY (self.bounds));
    CGRect matteFrameRect = rect;
    
    UIColor *colour = [UIColor whiteColor];
    [colour setFill];
    colour = [UIColor grayColor];
    [colour setStroke];
    CGContextSetLineWidth (context, 1.0);
    
    CGFloat MatteWidthTotal = 2.0 * SWSnapshotStackViewMatteWidth;
    
    if (NO == m_displayStack) {
        CGSize scaledImageSize;
        if (m_imageAspect > 1.0) {
            CGFloat targetWidth = self.frame.size.width - MatteWidthTotal;
            scaledImageSize = CGSizeMake (targetWidth, targetWidth / m_imageAspect);
        } else {
            CGFloat targetHeight = self.frame.size.height - MatteWidthTotal - SWSnapshotStackViewSingleShadowTotalHeight;
            scaledImageSize = CGSizeMake (targetHeight * m_imageAspect, targetHeight);
        }
        
        matteFrameRect = CGRectMake (floorf (viewCenter.x - ((scaledImageSize.width / 2.0) + SWSnapshotStackViewMatteWidth)) + 0.5,
                                     floorf (viewCenter.y - ((scaledImageSize.height / 2.0) + SWSnapshotStackViewMatteWidth + (SWSnapshotStackViewSingleShadowTotalHeight / 2.0))) + 0.5,
                                     floorf (scaledImageSize.width + MatteWidthTotal) - 1.0,
                                     floorf (scaledImageSize.height + MatteWidthTotal) - 1.0);
        
        CGContextSaveGState (context);
        
        CGMutablePathRef shadowPath = CGPathCreateMutable ();
        CGPathMoveToPoint (shadowPath, NULL,
                           matteFrameRect.origin.x + SWSnapshotStackViewSingleShadowXOffset,
                           matteFrameRect.origin.y + matteFrameRect.size.height - SWSnapshotStackViewSingleShadowTotalHeight);
        CGPathAddLineToPoint (shadowPath, NULL,
                              matteFrameRect.origin.x + matteFrameRect.size.width - SWSnapshotStackViewSingleShadowXOffset,
                              matteFrameRect.origin.y + matteFrameRect.size.height - SWSnapshotStackViewSingleShadowTotalHeight);
        CGPathAddLineToPoint (shadowPath, NULL,
                              matteFrameRect.origin.x + matteFrameRect.size.width - SWSnapshotStackViewSingleShadowXOffset,
                              matteFrameRect.origin.y + matteFrameRect.size.height);
        CGPathAddQuadCurveToPoint (shadowPath, NULL,
                                   (matteFrameRect.origin.x + matteFrameRect.size.width) / 2.0,
                                   matteFrameRect.origin.y + matteFrameRect.size.height - SWSnapshotStackViewSingleShadowTotalHeight,
                                   matteFrameRect.origin.x + SWSnapshotStackViewSingleShadowXOffset,
                                   matteFrameRect.origin.y + matteFrameRect.size.height);
        CGPathCloseSubpath (shadowPath);
        
        // Draw the shadow using it's calculated path
        colour = [UIColor colorWithRed:0 green:0 blue:0.0 alpha:0.6];
        CGContextSetShadowWithColor (context, CGSizeMake (0, (SWSnapshotStackViewSingleShadowYOffset * m_shadowDirSign)),
                                     SWSnapshotStackViewSingleShadowRadius, colour.CGColor);
        CGContextAddPath (context, shadowPath);
        CGContextFillPath (context);
        CGPathRelease (shadowPath);
        
        CGContextRestoreGState (context);
        
        // Draw the matte frame
        CGPathRef matteFramePath = CGPathCreateWithRect (matteFrameRect, NULL);
        CGContextAddPath (context, matteFramePath);
        CGContextDrawPath (context, kCGPathFillStroke);
        CGPathRelease (matteFramePath);
    } else {
        CGFloat requiredScaling;
        if (YES == m_scaledUsingWidth) {
            requiredScaling = (self.frame.size.width - 1 - SWSnapshotStackViewStackShadowTotalHeight) /
            m_snapshotPositions[m_minScaleShotIdx].boundingRectSize.width;
        } else {
            requiredScaling = (self.frame.size.height - 1 - SWSnapshotStackViewStackShadowTotalHeight) /
            m_snapshotPositions[m_minScaleShotIdx].boundingRectSize.height;
        }
        
        CGSize matteSize = CGSizeMake (m_image.size.width * requiredScaling,
                                       m_image.size.height * requiredScaling);
        
        for (NSInteger shotIdx = 0; shotIdx < SWSnapshotStackViewSnapshotsPerStack; shotIdx++) {
            CGContextSaveGState (context);
            
            CGMutablePathRef matteFramePath = CGPathCreateMutable ();
            
            CGFloat angleRotation = (m_snapshotPositions[shotIdx].angleRotation) * (M_PI / 180.0);
            
            if (0.0 == angleRotation) {
                matteFrameRect =
                CGRectMake (floorf (viewCenter.x - (matteSize.width / 2.0)) + 0.5,
                            floorf (viewCenter.y - (matteSize.height / 2.0)) + 0.5,
                            floorf (matteSize.width), floorf (matteSize.height));
                CGPathAddRect (matteFramePath, NULL, matteFrameRect);
            } else {
                CGPoint P1;
                CGPoint P2;
                CGPoint P3;
                CGPoint P4;
                CGSize scaledBoudingRectSize = CGSizeMake ((m_snapshotPositions[shotIdx].boundingRectSize.width * requiredScaling),
                                                           (m_snapshotPositions[shotIdx].boundingRectSize.height * requiredScaling));
                
                CGFloat halfScaledBoundingRectWidth = (scaledBoudingRectSize.width / 2.0);
                CGFloat halfScaledBoundingRectHeight = (scaledBoudingRectSize.height / 2.0);
                CGFloat adjacentOnXAxis = scaledBoudingRectSize.height * sin (angleRotation);
                CGFloat adjacentOnYAxis = scaledBoudingRectSize.width * sin (angleRotation);
                
                if (angleRotation < 0.0) {
                    
                    P1 = CGPointMake (viewCenter.x - halfScaledBoundingRectWidth,
                                      viewCenter.y - halfScaledBoundingRectHeight - adjacentOnYAxis);
                    P2 = CGPointMake (viewCenter.x + halfScaledBoundingRectWidth + adjacentOnXAxis,
                                      viewCenter.y - halfScaledBoundingRectHeight);
                    P3 = CGPointMake (viewCenter.x + halfScaledBoundingRectWidth,
                                      viewCenter.y + halfScaledBoundingRectHeight + adjacentOnYAxis);
                    P4 = CGPointMake (viewCenter.x - halfScaledBoundingRectWidth - adjacentOnXAxis,
                                      viewCenter.y + halfScaledBoundingRectHeight);
                } else {
                    // Clockwise rotation
                    
                    P1 = CGPointMake (viewCenter.x - halfScaledBoundingRectWidth + adjacentOnXAxis,
                                      viewCenter.y - halfScaledBoundingRectHeight);
                    P2 = CGPointMake (viewCenter.x + halfScaledBoundingRectWidth,
                                      viewCenter.y - halfScaledBoundingRectHeight + adjacentOnYAxis);
                    P3 = CGPointMake (viewCenter.x + halfScaledBoundingRectWidth - adjacentOnXAxis,
                                      viewCenter.y + halfScaledBoundingRectHeight);
                    P4 = CGPointMake (viewCenter.x - halfScaledBoundingRectWidth,
                                      viewCenter.y + halfScaledBoundingRectHeight - adjacentOnYAxis);
                }
                
                // Create path to define the matte frame of the rotated snapshot
                CGPathMoveToPoint (matteFramePath, NULL, P1.x, P1.y);
                CGPathAddLineToPoint (matteFramePath, NULL, P2.x, P2.y);
                CGPathAddLineToPoint (matteFramePath, NULL, P3.x, P3.y);
                CGPathAddLineToPoint (matteFramePath, NULL, P4.x, P4.y);
                CGPathCloseSubpath (matteFramePath);
            }
            
            CGContextSaveGState (context);

            colour = [UIColor colorWithRed:0 green:0 blue:0.0 alpha:0.4];
            CGContextSetShadowWithColor (context, CGSizeMake (0.0, (SWSnapshotStackViewStackShadowYOffset * m_shadowDirSign)),
                                         SWSnapshotStackViewStackShadowRadius, colour.CGColor);
            CGContextAddPath (context, matteFramePath);
            CGContextFillPath (context);
            
            CGContextRestoreGState (context);
            
            // Draw the matte frame
            CGContextAddPath (context, matteFramePath);
            CGContextDrawPath (context, kCGPathFillStroke);
            CGPathRelease (matteFramePath);
            
            CGContextRestoreGState (context);
        }
        
    }
    CGRect imageFrame = matteFrameRect;
    imageFrame.origin.x += SWSnapshotStackViewMatteWidth - 0.5;
    imageFrame.origin.y += SWSnapshotStackViewMatteWidth - 0.5;
    imageFrame.size.width -= MatteWidthTotal - 1;
    imageFrame.size.height -= MatteWidthTotal - 1;
    
    [m_image drawInRect:imageFrame];
}


- (void)calculateScalingToFitStack {
    CGFloat requiredScaling = 1.0;
    
    for (NSInteger idx = 0; idx < SWSnapshotStackViewSnapshotsPerStack; idx++)  {
   
        CGSize imageSize = m_image.size;
        CGFloat angleRotation = 
        (fabs(m_snapshotPositions[idx].angleRotation) * (M_PI / 180.0));
        CGSize boundingRect = CGSizeMake ((imageSize.width * cos (angleRotation)) +
                                          (imageSize.height * sin (angleRotation)),
                                          (imageSize.width * sin (angleRotation)) +
                                          (imageSize.height * cos (angleRotation)));
        m_snapshotPositions[idx].boundingRectSize = boundingRect;
        
    
        CGFloat requiredWidthScaling = self.frame.size.width / boundingRect.width;
        CGFloat requiredHeightScaling = self.frame.size.height / boundingRect.height;
        
        if (requiredWidthScaling < requiredScaling) {
            requiredScaling = requiredWidthScaling;
            m_minScaleShotIdx = idx;
            m_scaledUsingWidth = YES;
        }
        if (requiredHeightScaling < requiredScaling) {
            requiredScaling = requiredHeightScaling;
            m_minScaleShotIdx = idx;   
            m_scaledUsingWidth = NO;
        }
    }
}

@end
